using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace DrawLine
{
    public partial class DrawLine : Form
    {
        private List<Screen> mScreens;
        private int mCurrentScreen;
        private Pen mPen;
        private Stroke mCurrentStroke;

        public DrawLine()
        {
            InitializeComponent();

            this.mCurrentScreen = 0;
            this.mScreens = new List<Screen>();
            this.mScreens.Add(new Screen(0));
            this.mPen = Resources.GetPen(this.btnPenColor.BackColor, Convert.ToSingle(this.numPenSize.Value));

            this.panCanvas.Width = Variables.CANVAS_WIDTH;
            this.panCanvas.Height = Variables.CANVAS_HEIGHT;
            this.panImage.Width = this.GetThumbnailRect(0).Right    // right edge of thumbnail
                                + Variables.THUMBNAIL_BORDER        // right border
                                + Variables.THUMBNAIL_SPACE;        // right space
        }

        private void panCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.mCurrentStroke.Points.Count > 0)
                {
                    Graphics graphics = this.panCanvas.CreateGraphics();
                    graphics.SmoothingMode = SmoothingMode.HighQuality;
                    Point lastPoint = this.mCurrentStroke.Points[this.mCurrentStroke.Points.Count - 1];
                    graphics.DrawLine(this.mPen, lastPoint, e.Location);
                    graphics.Dispose();
                }
                this.mCurrentStroke.Points.Add(e.Location);
            }
        }

        private void panCanvas_MouseDown(object sender, MouseEventArgs e)
        {
            this.mCurrentStroke = new Stroke(this.mPen.Color, this.mPen.Width);
            this.mCurrentStroke.Points.Add(e.Location);
        }

        private void panCanvas_MouseUp(object sender, MouseEventArgs e)
        {
            this.mScreens[this.mCurrentScreen].AddStroke(this.mCurrentStroke);
            this.panImage.Invalidate();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            // refresh
            this.panCanvas.Invalidate();
        }

        private void btnNewSlide_Click(object sender, EventArgs e)
        {
            // create new slide
            this.mCurrentScreen = this.mScreens.Count;
            this.mScreens.Add(new Screen(this.mScreens.Count));
            this.lblSlideCount.Text = String.Format("{0} / {1}", this.mCurrentScreen + 1, this.mCurrentScreen + 1);
            this.panImage.Invalidate();
            this.panCanvas.Invalidate();
        }

        private void btnClearSlide_Click(object sender, EventArgs e)
        {
            // clear current slide
            this.mScreens[this.mCurrentScreen].Clear();
            this.panImage.Invalidate();
            this.panCanvas.Invalidate();
        }

        private void btnSaveSlide_Click(object sender, EventArgs e)
        {
            // save slide
            this.mScreens[this.mCurrentScreen].Save();
        }

        private void btnPenColor_Click(object sender, EventArgs e)
        {
            // show the color picker
            ColorDialog colorDlg = new ColorDialog();
            colorDlg.Color = this.mPen.Color;
            if (colorDlg.ShowDialog() == DialogResult.OK)
            {
                this.mPen = Resources.GetPen(colorDlg.Color, this.mPen.Width);
                this.btnPenColor.BackColor = colorDlg.Color;
            }
        }

        private void numPenSize_ValueChanged(object sender, EventArgs e)
        {
            this.mPen = Resources.GetPen(this.mPen.Color, Convert.ToSingle(this.numPenSize.Value));
        }

        private void panCanvas_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bitmap = new Bitmap(panCanvas.Width, panCanvas.Height))
            {
                Graphics bitmapGraphics = Graphics.FromImage(bitmap);
                this.mScreens[this.mCurrentScreen].Draw(bitmapGraphics, 1.0f);
                e.Graphics.DrawImageUnscaled(bitmap, 0, 0);
            }
        }

        private void panImage_Paint(object sender, PaintEventArgs e)
        {
            using (Bitmap bitmap = new Bitmap(panImage.Width, panImage.Height))
            {
                Graphics bitmapGraphics = Graphics.FromImage(bitmap);

                int expectedHeight = this.GetThumbnailRect(Math.Max(1, this.mScreens.Count - 1)).Bottom 
                                    + Variables.THUMBNAIL_BORDER
                                    + Variables.THUMBNAIL_SPACE;
                if (this.panImage.Height != expectedHeight)
                {
                    this.panImage.Height = expectedHeight;
                }

                Pen blackPen = Resources.GetPen(Color.Black, 1.0f);
                Pen selectedPen = Resources.GetPen(Color.Red, Variables.THUMBNAIL_BORDER);
                Graphics thumbnailGraphics;
                Rectangle expectedRect;

                using (Bitmap thumbnail = new Bitmap(Variables.THUMBNAIL_WIDTH, Variables.THUMBNAIL_HEIGHT))
                {
                    foreach (Screen screen in this.mScreens)
                    {
                        // get the rectangle associated with screen
                        expectedRect = this.GetThumbnailRect(screen.ID);

                        // get the graphics for the bitmap
                        thumbnailGraphics = Graphics.FromImage(thumbnail);
                        thumbnailGraphics.FillRectangle(Brushes.White, 0, 0, Variables.THUMBNAIL_WIDTH, Variables.THUMBNAIL_HEIGHT);
                        screen.Draw(thumbnailGraphics, ((float)Variables.THUMBNAIL_WIDTH / (float)Variables.CANVAS_WIDTH));
                        thumbnailGraphics.Dispose();

                        // now draw it
                        bitmapGraphics.DrawImageUnscaled(thumbnail, expectedRect.Location);

                        if (screen.ID == this.mCurrentScreen)
                        {
                            // draw selected outline
                            Rectangle borderRect = new Rectangle(expectedRect.Location, expectedRect.Size);
                            borderRect.Inflate(Variables.THUMBNAIL_BORDER - (Variables.THUMBNAIL_BORDER / 2),
                                                Variables.THUMBNAIL_BORDER - (Variables.THUMBNAIL_BORDER / 2));
                            bitmapGraphics.DrawRectangle(selectedPen, borderRect);
                        }

                        // draw the outline
                        bitmapGraphics.DrawRectangle(blackPen, expectedRect);
                    }
                }

                // dispose the bitmap graphics
                bitmapGraphics.Dispose();

                // now draw the bitmap into the panImage
                e.Graphics.DrawImageUnscaled(bitmap, 0, 0);
            }
        }

        private void panImage_MouseDown(object sender, MouseEventArgs e)
        {
            // select something
            if ((e.X > Variables.THUMBNAIL_BORDER) &&
                (e.X < (Variables.THUMBNAIL_WIDTH + Variables.THUMBNAIL_BORDER + Variables.THUMBNAIL_SPACE)))
            {
                // calculate the Y position
                for (int i = 0; i < this.mScreens.Count; i++)
                {
                    Rectangle expectedRect = this.GetThumbnailRect(i);
                    if (expectedRect.Contains(e.Location))
                    {
                        this.mCurrentScreen = i;
                        this.panCanvas.Invalidate();
                        this.panImage.Invalidate();
                        this.lblSlideCount.Text = String.Format("{0} / {1}", this.mCurrentScreen + 1, this.mScreens.Count);
                        break;
                    }
                }
            }
        }


        private Rectangle GetThumbnailRect(int thumbnailIndex)
        {
            // compute x
            int x = (Variables.THUMBNAIL_SPACE          // left margin
                + Variables.THUMBNAIL_BORDER);          // left border

            // compute y
            int y = (Variables.THUMBNAIL_SPACE          // first margin
                    + Variables.THUMBNAIL_BORDER)       // first border
                    + ((Variables.THUMBNAIL_SPACE       // space between thumbnails
                    + Variables.THUMBNAIL_BORDER        // top border
                    + Variables.THUMBNAIL_HEIGHT        // height of thumbnail
                    + Variables.THUMBNAIL_BORDER)       // bottom border
                    * thumbnailIndex);                  // thumbnail index

            // return the rectangle
            return new Rectangle(x, y, Variables.THUMBNAIL_WIDTH, Variables.THUMBNAIL_HEIGHT);
        }
    }
}